package com.skt.utils;

import com.skt.domain.ENUM.LogLevel;  // 注意：这里应该是enums不是ENUM
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 日志工具类封装
 * 提供统一的日志记录、性能监控、业务追踪等功能
 */
@Slf4j
@Component
public class LogUtil {

    // 1. 性能监控计时器
    private static final ThreadLocal<StopWatch> STOP_WATCH_THREAD_LOCAL = new ThreadLocal<>();
    // 2. 业务上下文存储
    private static final ThreadLocal<Map<String, Object>> BUSINESS_CONTEXT_THREAD_LOCAL = new ThreadLocal<>();

    // ========== 基础日志方法 ==========

    /**
     * 记录业务日志
     */
    public static void log(LogLevel level, String module, String operation, String message, Object... args) {
        String formattedMessage = formatMessage(module, operation, message, args);
        switch (level) {
            case TRACE:
                log.trace(formattedMessage);
                break;
            case DEBUG:
                log.debug(formattedMessage);
                break;
            case INFO:
                log.info(formattedMessage);
                break;
            case WARN:
                log.warn(formattedMessage);
                break;
            case ERROR:
                log.error(formattedMessage);
                break;
            default:
                log.info(formattedMessage);
        }
    }

    /**
     * 记录带上下文的业务日志
     */
    public static void logWithContext(LogLevel level, String module, String operation,
                                      Map<String, Object> context, String message, Object... args) {
        StringBuilder sb = new StringBuilder(formatMessage(module, operation, message, args));
        if (context != null && !context.isEmpty()) {
            sb.append(" | Context: ").append(context);
        }

        switch (level) {
            case TRACE:
                log.trace(sb.toString());
                break;
            case DEBUG:
                log.debug(sb.toString());
                break;
            case INFO:
                log.info(sb.toString());
                break;
            case WARN:
                log.warn(sb.toString());
                break;
            case ERROR:
                log.error(sb.toString());
                break;
            default:
                log.info(sb.toString());
        }
    }

    // ========== 快捷方法 ==========

    public static void info(String module, String operation, String message, Object... args) {
        log(LogLevel.INFO, module, operation, message, args);
    }

    public static void warn(String module, String operation, String message, Object... args) {
        log(LogLevel.WARN, module, operation, message, args);
    }

    public static void error(String module, String operation, String message, Object... args) {
        log(LogLevel.ERROR, module, operation, message, args);
    }

    public static void debug(String module, String operation, String message, Object... args) {
        log(LogLevel.DEBUG, module, operation, message, args);
    }

    // ========== 业务场景专用方法 ==========

    /**
     * 购物车操作日志
     */
    public static void cartInfo(Long userId, String operation, String message, Object... args) {
        Map<String, Object> context = new HashMap<>();
        context.put("userId", userId);
        context.put("operation", operation);
        logWithContext(LogLevel.INFO, "CART", operation, context, message, args);
    }

    /**
     * 购物车错误日志
     */
    public static void cartError(Long userId, String operation, String errorMsg, Throwable e) {
        Map<String, Object> context = new HashMap<>();
        context.put("userId", userId);
        context.put("operation", operation);
        context.put("error", errorMsg);

        String formattedMessage = "购物车操作失败: " + errorMsg;
        logWithContext(LogLevel.ERROR, "CART", operation, context, formattedMessage);
        if (e != null) {
            log.error("详细异常信息: ", e);
        }
    }

    /**
     * 性能监控开始
     */
    public static void startTimer(String operation) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start(operation);
        STOP_WATCH_THREAD_LOCAL.set(stopWatch);

        log.debug("[PERF::{}] 开始计时: {}", operation, operation);
    }

    /**
     * 性能监控结束
     */
    public static void stopTimer() {
        StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
        if (stopWatch != null && stopWatch.isRunning()) {
            stopWatch.stop();
            log.info("[PERF::{}] 操作耗时: {}ms",
                    stopWatch.getLastTaskName(), stopWatch.getLastTaskTimeMillis());
            STOP_WATCH_THREAD_LOCAL.remove();
        }
    }

    /**
     * 设置追踪ID
     */
    public static void setTraceId() {
        setTraceId(UUID.randomUUID().toString());
    }

    /**
     * 设置追踪ID
     */
    public static void setTraceId(String traceId) {
        MDC.put("traceId", traceId);
    }

    /**
     * 获取追踪ID
     */
    public static String getTraceId() {
        return MDC.get("traceId");
    }

    /**
     * 清理上下文
     */
    public static void clearContext() {
        MDC.clear();
        STOP_WATCH_THREAD_LOCAL.remove();
        if (BUSINESS_CONTEXT_THREAD_LOCAL.get() != null) {
            BUSINESS_CONTEXT_THREAD_LOCAL.get().clear();
            BUSINESS_CONTEXT_THREAD_LOCAL.remove();
        }
    }

    // ========== 私有方法 ==========

    /**
     * 格式化消息
     */
    private static String formatMessage(String module, String operation, String message, Object[] args) {
        String baseMessage = String.format("[%s::%s] %s", module, operation, message);

        if (args != null && args.length > 0) {
            try {
                return String.format(baseMessage.replace("{}", "%s"), args);
            } catch (Exception e) {
                log.warn("日志格式化失败，使用原始消息: {}", baseMessage);
                return baseMessage;
            }
        }
        return baseMessage;
    }
}